from bopress import options, metas
from bopress.forms import ProfileForm, FormData, UserForm
from bopress.hook import add_action, add_menu_page, add_submenu_page, add_option_page, add_filter, do_action
from bopress.log import Logger
from bopress.mail import Mailer
from bopress.model import Users
from bopress.orm import SessionFactory
from bopress.utils import Utils


def bo_options_general_save(handler):
    if handler.auth({'manage_options'}):
        opt_name = handler.get_argument("option_name")
        if not opt_name:
            handler.render_json(success=False)
        else:
            params = dict()
            for p in handler.request.arguments.keys():
                if p.startswith("opt_"):
                    k = p.replace("opt_", "")
                    params[k] = handler.get_arguments(p)

            options.save_options(opt_name, params)
            handler.render_json(success=True)


def bo_options_general_get(handler):
    if handler.auth({'manage_options'}):
        opt_name = handler.get_argument("option_name")
        if not opt_name:
            handler.render_json(success=False)
        else:
            opt_value = options.get_options(opt_name)
            handler.render_json(success=True, data=opt_value)


def bo_role_caps_load(handler):
    if handler.auth({'list_users'}):
        v = options.get_options("bo_capabilities")
        vv = options.get_options("bo_roles")
        r = dict()
        r["roles"] = sorted(vv.items(), key=lambda d: d[0])
        r["caps"] = sorted(v.items(), key=lambda d: d[0])
        c_arr = list()
        c_set = set()
        for c in v.values():
            c_set.add(c[0])
            c_arr.append(c[0])
        c_map = dict()
        for i in c_set:
            n = c_arr.count(i)
            c_map[i] = n
        r["groups"] = sorted(c_map.items(), key=lambda d: d[0])
        handler.render_json(success=True, data=r)


def bo_role_caps_add(handler):
    if handler.auth({'list_users'}):
        name = handler.get_argument("name")
        display_name = handler.get_argument("display_name")
        copy_name = handler.get_argument("copy_name")
        if name:
            vv = options.get_options("bo_roles")
            if name in vv.keys():
                handler.render_json(success=False, msg="Exists")
            else:
                caps = list()
                if copy_name:
                    caps = vv[copy_name][1]
                vv[name] = [display_name, caps]
                options.save_options("bo_roles", vv)
                handler.render_json(success=True)


def bo_role_caps_rename(handler):
    if handler.auth({'list_users'}):
        name = handler.get_argument("name")
        display_name = handler.get_argument("display_name")
        if name:
            vv = options.get_options("bo_roles")
            if name not in vv.keys():
                handler.render_json(success=False, msg="No Exists")
            else:
                vv[name][0] = display_name
                options.save_options("bo_roles", vv)
                handler.render_json(success=True)


def bo_role_caps_save(handler):
    if handler.auth({'list_users'}):
        name = handler.get_argument("current_edit_role_name")
        caps = handler.get_arguments("bo_role_cap_item")
        if name:
            vv = options.get_options("bo_roles")
            if name not in vv.keys():
                handler.render_json(success=False, msg="No Exists")
            else:
                vv[name][1] += caps
                vv[name][1] = list(set(vv[name][1]))
                options.save_options("bo_roles", vv)
                handler.render_json(success=True)


def bo_users_list_view(handler):
    if handler.auth({'list_users'}):
        s = SessionFactory.session()
        total = s.query(Users).count()
        ds = s.query(Users).all()
        data = list()
        for item in ds:
            a = dict()
            a["user_login"] = item.user_login
            a["user_nicename"] = item.user_nicename
            a["user_email"] = item.user_email
            a["user_mobile_phone"] = item.user_mobile_phone
            a["user_registered"] = item.user_registered
            a["user_status"] = item.user_status
            a["display_name"] = item.display_name
            a["user_id"] = item.user_id
            data.append(a)
        handler.render_datatables(data, total, total)


def bo_users_get(handler):
    if handler.auth({'list_users'}):
        pk = handler.get_argument("pk", 0)
        s = SessionFactory.session()
        u = s.query(Users).get(int(pk))
        if u:
            a = dict()
            a["user_login"] = u.user_login
            a["user_nicename"] = u.user_nicename
            a["user_email"] = u.user_email
            a["user_mobile_phone"] = u.user_mobile_phone
            a["user_status"] = u.user_status
            a["display_name"] = u.display_name
            a["user_id"] = u.user_id
            a["user_roles"] = list(metas.get_user_metas(u.user_id, "bo_roles"))
            handler.render_json(a)
        else:
            handler.render_json("", "", False)


def bo_users_save(handler):
    """
    修改用户基本资料
    :param handler: RequestHandler
    """
    if handler.auth({'list_users'}):
        f = UserForm(FormData(handler))
        if f.validate():
            pk = handler.get_argument("user_id", None)
            site_options = options.get_site_options()
            s = SessionFactory.session()
            if pk:
                if handler.auth({'edit_users'}):
                    int_pk = int(pk)
                    email_exists = s.query(Users).filter(Users.user_email == f.user_email.data) \
                        .filter(Users.user_id != int_pk).count()
                    phone_exists = s.query(Users).filter(Users.user_mobile_phone == f.user_mobile_phone.data) \
                        .filter(Users.user_id != int_pk).count()
                    if email_exists > 0:
                        handler.render_json("", "邮箱已被使用", False)
                    elif phone_exists > 0:
                        handler.render_json("", "手机已被使用", False)
                    else:
                        u = s.query(Users).get(int_pk)
                        f.populate_obj(u)
                        s.commit()
                        metas.save_user_metas(u.user_id, "bo_roles", set(handler.get_arguments("user_roles")))
                        handler.render_json()
            else:
                if handler.auth({'create_users'}):
                    email_exists = s.query(Users).filter(Users.user_email == f.user_email.data).count()
                    phone_exists = s.query(Users).filter(Users.user_mobile_phone == f.user_mobile_phone.data).count()
                    if email_exists > 0:
                        handler.render_json("", "邮箱已被使用", False)
                    elif phone_exists > 0:
                        handler.render_json("", "手机已被使用", False)
                    else:
                        u = Users()
                        f.populate_obj(u)
                        pwd = Utils.random_str(8)
                        u.user_pass = Utils.md5(pwd)
                        u.user_activation_key = Utils.uniq_index()
                        u.user_registered = Utils.current_datetime()
                        s.add(u)
                        s.commit()
                        metas.save_user_metas(u.user_id, "bo_super", False)
                        metas.save_user_metas(u.user_id, "bo_roles", set(handler.get_arguments("user_roles")))
                        metas.save_user_metas(u.user_id, "bo_description", "")
                        metas.save_user_metas(u.user_id, "bo_gravatar", "")
                        try:
                            link = "%s%s?ak=%s" % (site_options.get("site_url"),
                                                   handler.reverse_url("verify"), u.user_activation_key)
                            title = "新用户激活"
                            body = """
                            <html><body>点此链接激活账户: <a href="%s">%s</a></body></html>
                            """ % (link, link)
                            Mailer.send_mail([u.user_email], title, body)
                        except Exception as e:
                            Logger.exception(e)
                        handler.render_json()
        else:
            handler.render_json(f.errors, "", False)


def site_settings_form(form, screen_id, handler):
    if screen_id == "bo-site-settings":
        opts = options.get_form_options("bo-site-settings")
        if opts.empty():
            site_url = "%s://%s" % (handler.request.protocol, handler.request.host)
            default_value = dict()
            default_value["site_url"] = [site_url]
            default_value["site_email"] = [""]
            default_value["users_can_register"] = ["Y"]
            default_value["default_role"] = ["subscriber"]
            options.save_options("bo-site-settings", default_value)
        roles = options.get_options("bo_roles")
        roles_html = list()
        roles_html.append('<div class="form-group">')
        roles_html.append('<label for="default_role">新用户默认角色</label>')
        roles_html.append('<select class="form-control option" id="default_role" name="opt_default_role">')
        for role in roles:
            roles_html.append('<option value="' + role + '">' + roles[role][0] + '</option>')
        roles_html.append('</select>')
        roles_html.append('</div>')

        form = """
        <div class="form-group">
          <label for="site_url">域名</label>
          <input type="text" class="form-control option" id="site_url" name="opt_site_url" placeholder="">
        </div>
        <div class="form-group">
          <label for="site_email">管理员邮箱</label>
          <input type="text" class="form-control option" id="site_email" name="opt_site_email" placeholder="">
        </div>
        <div class="form-group">
          <label for="users_can_register">任何人都可以注册</label>
          <select class="form-control option" id="users_can_register" name="opt_users_can_register">
          <option value="Y">是</option>
          <option value="N">否</option>
          </select>
        </div>
        %s
        """ % "".join(roles_html)
    return form


def site_settings_options_group_name(group_name, screen_id, handler):
    if screen_id == "bo-site-settings":
        group_name = "bo-site-settings"
    return group_name


def smtp_server_settings_form(form, screen_id, handler):
    if screen_id == "bo-smtp-settings":
        form = """
        <div class="form-group">
          <label for="smtp_server">服务器</label>
          <input type="text" class="form-control option" id="smtp_server" name="opt_smtp_server" placeholder="">
        </div>
        <div class="form-group">
          <label for="smtp_port">端口</label>
          <input type="number" class="form-control option" id="smtp_port" name="opt_smtp_port" placeholder="端口">
        </div>
        <div class="form-group">
          <label for="smtp_auth">账号认证</label>
          <select class="form-control option" id="smtp_auth" name="opt_smtp_auth">
          <option value="Y">是</option>
          <option value="N">否</option>
          </select>
        </div>
        <div class="form-group">
          <label for="smtp_security">安全连接</label>
          <select class="form-control option" id="smtp_security" name="opt_smtp_security">
          <option value="">无</option>
          <option value="ssl">ssl</option>
          <option value="tls">tls</option>
          </select>
        </div>
        <div class="form-group">
          <label for="smtp_user_name">账号</label>
          <input type="text" class="form-control option" id="smtp_user_name" name="opt_user_name" placeholder="账号">
        </div>
        <div class="form-group">
          <label for="smtp_user_pass">密码</label>
          <input type="password" class="form-control option" id="smtp_user_pass" name="opt_user_pass" placeholder="密码">
        </div>
        <div class="form-group">
          <label for="smtp_from">发件人地址</label>
          <input type="email" class="form-control option" id="smtp_from" name="opt_smtp_from" placeholder="发件人地址">
        </div>
        <div class="form-group">
          <label for="smtp_from_name">发件人姓名</label>
          <input type="text" class="form-control option" id="smtp_from_name" name="opt_smtp_from_name" placeholder="发件人姓名">
        </div>
        """
    return form


def smtp_server_settings_options_group_name(group_name, screen_id, handler):
    if screen_id == "bo-smtp-settings":
        group_name = "bo-smtp-settings"
    return group_name


def bo_profile_page(handler, current_menu_item, screen_id):
    s = SessionFactory.session()
    u = s.query(Users).filter(Users.user_id == handler.get_current_user()).one_or_none()
    description = metas.get_user_metas(handler.get_current_user(), "bo_description")
    gravatar = metas.get_user_metas(handler.get_current_user(), "bo_gravatar")
    info = dict()
    info["description"] = description
    info["gravatar"] = gravatar
    handler.render("admin/profile.html", current_menu_item=current_menu_item, screen_id=screen_id, user=u, info=info)


def bo_users_page(handler, current_menu_item, screen_id):
    c = options.get_options("bo_roles")
    handler.render("admin/users.html", current_menu_item=current_menu_item, screen_id=screen_id, roles=c)


def bo_profile_save(handler):
    if handler.auth({'read'}):
        f = ProfileForm(FormData(handler))
        if f.validate():
            s = SessionFactory.session()
            u = s.query(Users).filter(Users.user_id == handler.get_current_user()).one_or_none()
            if u:
                f.populate_obj(u)
                send_email = False
                if f.new_pass.data:
                    u.user_pass = Utils.md5(f.new_pass.data)
                    send_email = True
                s.commit()
                metas.save_user_metas(handler.get_current_user(), "bo_description", f.description.data)
                metas.save_user_metas(handler.get_current_user(), "bo_gravatar", f.gravatar.data)
                if send_email:
                    Mailer.send_mail([u.user_email], "密码修改", "新密码: %s" % f.new_pass.data, "plain")
                handler.render_json()
            else:
                handler.render_json("", "错误", False)
        else:
            handler.render_json(f.errors, "", False)


def init_data():
    v = options.get_options("bo_capabilities")
    if not v:
        c = dict()
        # general 组
        c["read"] = ("general", "浏览")
        # user 组
        c["list_users"] = ("user", "查看用户列表")
        c["create_users"] = ("user", "创建用户")
        c["edit_users"] = ("user", "编辑用户")
        c["delete_users"] = ("user", "删除用户")
        # file 组
        c["edit_files"] = ("file", "编辑附件")
        c["upload_files"] = ("file", "上传附件")
        # admin 组
        c["manage_options"] = ("admin", "管理选项")
        options.save_options("bo_capabilities", c)

    vv = options.get_options("bo_roles")
    if not vv:
        c = dict()
        c["subscriber"] = ["订阅者", ["read"]]
        options.save_options("bo_roles", c)

    # create super user
    s = SessionFactory.session()
    num = s.query(Users).count()
    if num == 0:
        u = Users()
        u.user_login = "super"
        u.user_pass = Utils.md5("super")
        u.user_status = 1
        u.user_email = "super@domain.com"
        u.user_nicename = "super"
        u.display_name = "super"
        u.user_registered = Utils.current_datetime()
        s.add(u)
        s.commit()
        metas.save_user_metas(u.user_id, "bo_super", True)
        metas.save_user_metas(u.user_id, "bo_roles", {"super"})

    do_action("bo_init")


def load():
    add_menu_page("仪表盘", "仪表盘", "bo-dashboard", ["read"], "admin/dashboard.html", "", 1)
    add_menu_page("设置", "设置", "bo-options-general", ["manage_options"], "admin/options-general.html", "", 100)
    add_menu_page("用户", "用户", "bo-users", ["list_users"], "admin/blank.html", "", 99)
    add_submenu_page("bo-users", "用户管理", "所有用户", "bo-users-list", ["list_users"], bo_users_page)
    add_submenu_page("bo-users", "角色权限", "角色权限", "bo-role-capabilities", ["list_users"],
                     "admin/user_role_capabilities.html")
    add_menu_page("个人中心", "个人中心", "bo-profile", ["read"], bo_profile_page, "", 1000, place='single')
    add_option_page("通用设置", "通用", "bo-site-settings", ["manage_options"])
    add_option_page("SMTP 邮件", "SMTP 邮件", "bo-smtp-settings", ["manage_options"])
    add_filter("bo_options_general_form", site_settings_form)
    add_filter("bo_options_general_name", site_settings_options_group_name)
    add_filter("bo_options_general_form", smtp_server_settings_form)
    add_filter("bo_options_general_name", smtp_server_settings_options_group_name)
    add_action("bo_api_post_bo_options_general_save", bo_options_general_save)
    add_action("bo_api_post_bo_options_general_get", bo_options_general_get)
    add_action("bo_api_post_bo_role_caps_load", bo_role_caps_load)
    add_action("bo_api_post_bo_role_caps_add", bo_role_caps_add)
    add_action("bo_api_post_bo_role_caps_rename", bo_role_caps_rename)
    add_action("bo_api_post_bo_role_caps_save", bo_role_caps_save)
    add_action("bo_api_post_bo_profile_save", bo_profile_save)
    add_action("bo_api_post_bo_users_list", bo_users_list_view)
    add_action("bo_api_post_bo_users_get", bo_users_get)
    add_action("bo_api_post_bo_users_save", bo_users_save)
